#include "animationeditor.h"
#include "../application.h"
#include "../document.h"
#include "../gameobjects/abstractobject.h"
#include "../gameobjects/animation.h"
#include "../gameobjects/texture.h"
#include "widgets/editanimationwidget.h"
#include "../widgets/objectview.h"
#include "../mainwindow.h"
#include "widgets/animationcontrolwidget.h"
#include <QPainter>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QUrl>

#define PREVIEW_FUNC() \
    EditAnimationWidget* pView = qobject_cast<EditAnimationWidget*>(m_view); \
    Q_ASSERT(pView); \
    AnimationView* pPreview = qobject_cast<AnimationView*>(pView->previewWidget()); \
    Q_ASSERT(pPreview);

#define ANIM_FUNC() \
    QPointer<Document> doc = Application::app().document(); \
    Q_ASSERT(doc); \
    QPointer<Animation> anim = qobject_cast<Animation*>(doc->currentObject()); \
    Q_ASSERT(anim);

AnimationEditor::AnimationEditor(QObject *parent) :
    AbstractEditor(parent)
{
}

bool AnimationEditor::init()
{
    m_view = new EditAnimationWidget;
    connect(m_view, SIGNAL(parametersChanged()),
            this, SLOT(onParametersChanged()));

    PREVIEW_FUNC();

    AnimationControlWidget* pAC = qobject_cast<AnimationControlWidget*>(pView->animationControl());
    connect(pView, SIGNAL(startStopAnimation()), pAC, SLOT(togglePlayback()));
    connect(pView, SIGNAL(rewind()), pAC, SLOT(rewind()));
    return true;
}

void AnimationEditor::activate()
{
    AbstractEditor::activate();

    ANIM_FUNC();
    m_currAnim = anim;
    PREVIEW_FUNC();

    pView->resetParameters(m_currAnim);

    AnimationControlWidget* pAC = qobject_cast<AnimationControlWidget*>(pView->animationControl());
    connect(pAC, SIGNAL(currentFrameChanged(int)), m_currAnim, SLOT(setCurrentFrame(int)));
    connect(m_currAnim, SIGNAL(currentFrameChanged(int)), pPreview, SLOT(update()));

    pAC->setNumFrames(m_currAnim->texture() ? m_currAnim->numFrames() : 0);
    pAC->setCurrentFrame(0);

    pPreview->setAnimation(m_currAnim);
    pPreview->update();
}

void AnimationEditor::deactivate()
{
    AbstractEditor::deactivate();

    PREVIEW_FUNC();

    AnimationControlWidget* pAC = qobject_cast<AnimationControlWidget*>(pView->animationControl());
    pAC->stop();

    if(m_currAnim)
    {
        disconnect(pAC, SIGNAL(currentFrameChanged(int)), m_currAnim, SLOT(setCurrentFrame(int)));
        disconnect(m_currAnim, SIGNAL(currentFrameChanged(int)), pPreview, SLOT(update()));
        m_currAnim = 0;
    }
}

void AnimationEditor::onParametersChanged()
{
    PREVIEW_FUNC();

    int xPattern;
    int yPattern;
    int numFrames;
    bool bLoop;
    int nSpeed;
    pView->getParams(xPattern, yPattern, numFrames, bLoop, nSpeed);

    m_currAnim->generateAnimation(xPattern, yPattern, numFrames);

    AnimationControlWidget* pAC = qobject_cast<AnimationControlWidget*>(pView->animationControl());
    pAC->setNumFrames(numFrames);

    if(QPointer<Texture> texture = m_currAnim->texture())
    {
        pPreview->setAnimation(m_currAnim);
        pPreview->update();
    }
}


AnimationEditor::AnimationView::AnimationView(QWidget *parent)
    : m_bShowZoomOptions(false)
    , m_bZoomInMouseOver(false)
    , m_bZoomOutMouseOver(false)
    , m_fZoomFactor(1.0f)
{
    setAcceptDrops(true);
    m_pixZoomIn = QPixmap(":/gui/zoomIn");
    Q_ASSERT(!m_pixZoomIn.isNull());
    m_pixZoomOut = QPixmap(":/gui/zoomOut");
    Q_ASSERT(!m_pixZoomOut.isNull());
    setMouseTracking(true);

    m_zoomInPos = QPoint(10, 10);
    m_zoomOutPos = QPoint(50, 10);
}

void AnimationEditor::AnimationView::paintEvent(QPaintEvent *pEvent)
{
    QPainter painter(this);
    painter.fillRect(rect(), Qt::white);

    if(!m_anim)
    {
        return;
    }

    QPointer<Texture> tex = m_anim->texture();
    if(!tex)
    {
        painter.save();
        QFont f = font();
        f.setPixelSize(20);
        painter.setFont(f);
        painter.drawText(rect(), Qt::AlignCenter, "Create new texture or drag texture file...");
        painter.restore();
        return;
    }

    QPixmap pm = tex->pixmap();
    if(pm.isNull())
    {
        return;
    }

    QRect currFrameRect = m_anim->currentFrame().rect;

    painter.save();
    //painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(rect().width()/2, rect().height()/2);
    painter.scale(m_fZoomFactor, m_fZoomFactor);
    painter.drawPixmap(QPoint(-currFrameRect.width()/2, -currFrameRect.height()/2), pm, currFrameRect);

    painter.setPen(Qt::DotLine);
    painter.drawRect(QRect(-currFrameRect.width()/2, -currFrameRect.height()/2, currFrameRect.width(), currFrameRect.height()));
    painter.restore();

    if(m_bShowZoomOptions)
    {
        if(m_bZoomInMouseOver)
        {
            painter.setOpacity(1);
        }
        else
        {
            painter.setOpacity(0.5);
        }

        painter.drawPixmap(m_zoomInPos, m_pixZoomIn);


        if(m_bZoomOutMouseOver)
        {
            painter.setOpacity(1);
        }
        else
        {
            painter.setOpacity(0.5);
        }

        painter.drawPixmap(m_zoomOutPos, m_pixZoomOut);
    }
}


void AnimationEditor::AnimationView::setAnimation(QPointer<Animation> anim)
{
    m_anim = anim;
    // reset zoom factor
    m_fZoomFactor = 1.0f;
}

void AnimationEditor::AnimationView::dragEnterEvent(QDragEnterEvent *pEvent)
{
    QList<QUrl> listUrls = pEvent->mimeData()->urls();

    if(listUrls.size())
    {
         QString url = listUrls[0].toString();
         if(url.contains(".png"))
         {
             pEvent->acceptProposedAction();
         }
    }
}

void AnimationEditor::AnimationView::dropEvent(QDropEvent *pEvent)
{
    QString path = pEvent->mimeData()->urls().at(0).toString();
    path.remove("file:///");

    ANIM_FUNC();
    doc->createTexture("Texture", qobject_cast<AbstractObject*>(anim), path);

    QPointer<ObjectView> ov = Application::app().mainWindow()->objectView();
    ov->selectObject(qobject_cast<AbstractObject*>(anim));
}


void AnimationEditor::AnimationView::mousePressEvent(QMouseEvent *pEvent)
{
    if(zoomInRect().contains(pEvent->pos()))
    {
        m_fZoomFactor += 0.5f;
        if(m_fZoomFactor > 5.0f)
        {
            m_fZoomFactor = 5.0f;
        }
        update();
    }
    else if(zoomOutRect().contains(pEvent->pos()))
    {
        m_fZoomFactor -= 0.5f;
        if(m_fZoomFactor < 0.5f)
        {
            m_fZoomFactor = 0.5f;
        }
        update();
    }
}

void AnimationEditor::AnimationView::mouseMoveEvent(QMouseEvent *pEvent)
{
    if(zoomInRect().contains(pEvent->pos()))
    {
        m_bZoomInMouseOver = true;
    }
    else
    {
        m_bZoomInMouseOver = false;
    }

    if(zoomOutRect().contains(pEvent->pos()))
    {
        m_bZoomOutMouseOver = true;
    }
    else
    {
        m_bZoomOutMouseOver = false;
    }

    update();
}

void AnimationEditor::AnimationView::mouseReleaseEvent(QMouseEvent *pEvent)
{
}

void AnimationEditor::AnimationView::enterEvent(QEvent *pEvent)
{
    m_bShowZoomOptions = true;
    update();
}

void AnimationEditor::AnimationView::leaveEvent(QEvent *pEvent)
{
    m_bShowZoomOptions = false;
    update();
}


QRect AnimationEditor::AnimationView::zoomInRect() const
{
    return QRect(m_zoomInPos, m_pixZoomIn.size());
}

QRect AnimationEditor::AnimationView::zoomOutRect() const
{
    return QRect(m_zoomOutPos, m_pixZoomOut.size());
}
